package org.jetlinks.pro.notify.dingtalk;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hswebframework.web.utils.ExpressionUtils;
import org.jetlinks.pro.notify.template.Template;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Getter
@Setter
public class DingTalkWebHookTemplate implements Template {
    private MessageType messageType;

    private Text text;
    private Markdown markdown;
    private Link link;
    private At at;

    public void validate() {
        Assert.notNull(messageType, "messageType can not be null");

        switch (messageType) {
            case text:
                Assert.notNull(text, "text can not be null");
                break;
            case markdown:
                Assert.notNull(markdown, "markdown can not be null");
                break;
            case link:
                Assert.notNull(link, "link can not be null");
                break;
            default:
                throw new UnsupportedOperationException("unsupported messageType " + messageType);
        }
    }

    public JSONObject toJson(Map<String, Object> context) {
        validate();
        JSONObject json = new JSONObject();
        json.put("msgtype", messageType.name());
        if (at != null) {
            json.put("at", at.render(context).toJson());
        }
        switch (messageType) {
            case text:
                json.put("text", text.render(context).toJson());
                break;
            case markdown:
                json.put("markdown", markdown.render(context).toJson());
                break;
            case link:
                json.put("link", link.render(context).toJson());
                break;
        }
        return json;
    }

    public enum MessageType {
        text,
        link,
        markdown
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class At {
        private List<String> atMobiles;
        private List<String> atUserIds;
        private boolean atAll;

        public At render(Map<String, Object> context) {
            return new At(DingTalkWebHookTemplate.render(atMobiles, context),
                          DingTalkWebHookTemplate.render(atUserIds, context),
                          atAll);
        }

        public JSONObject toJson() {
            JSONObject json = new JSONObject();
            json.put("atMobiles", atMobiles);
            json.put("atUserIds", atUserIds);
            json.put("isAtAll", atAll);
            return json;
        }
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Text {
        private String content;

        public Text render(Map<String, Object> context) {
            return new Text(DingTalkWebHookTemplate.render(content, context));
        }

        public JSONObject toJson() {
            return new JSONObject(Collections.singletonMap("content", content));
        }
    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Markdown {
        private String title;
        private String text;

        public Markdown render(Map<String, Object> context) {
            return new Markdown(DingTalkWebHookTemplate.render(title, context),
                                DingTalkWebHookTemplate.render(text, context));
        }

        public JSONObject toJson() {
            JSONObject json = new JSONObject();
            json.put("title", title);
            json.put("text", text);
            return json;
        }

    }

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Link {
        private String title;
        private String picUrl;
        private String text;
        private String messageUrl;

        public Link render(Map<String, Object> context) {
            return new Link(DingTalkWebHookTemplate.render(title, context),
                            DingTalkWebHookTemplate.render(picUrl, context),
                            DingTalkWebHookTemplate.render(text, context),
                            DingTalkWebHookTemplate.render(messageUrl, context)
            );
        }

        public JSONObject toJson() {
            JSONObject json = new JSONObject();
            json.put("title", title);
            json.put("text", text);
            json.put("picUrl", picUrl);
            json.put("messageUrl", messageUrl);
            return json;
        }
    }

    private static List<String> render(List<String> templates, Map<String, Object> context) {
        return templates
            .stream()
            .map(template -> render(template, context))
            .collect(Collectors.toList());
    }

    private static String render(String template, Map<String, Object> context) {
        if (StringUtils.isEmpty(template)) {
            return template;
        }
        return ExpressionUtils.analytical(template, context, "spel");
    }
}
